home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / 3DSRDR12.ZIP / 3DSRDR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-30  |  20.2 KB  |  604 lines

  1. /* --------------------------- 3DSRDR.C -------------------------------
  2.     .3DS file format exerciser v1.2.
  3.     Written by Javier Arevalo, AKA Jare/Iguana.
  4.     I compile this with Watcom/32, but I guess it should work with
  5.         any compiler and OS combination for which the typedefs are
  6.         valid i.e. any that I know for PCs... Try it and see.
  7.         Oh, and also check the #pragma pack() thing.
  8.  
  9.     - DISCLAIMER -
  10.  
  11.     I hope I have not broken any patents or trade secrets by releasing
  12.         this info. This is purely a mind exercise to break into a file
  13.         format that is quite useful to know. As far as I have been told
  14.         a file format is not subject to anything such as copyright or
  15.         patent, so I have done this because I believe I'm allowed to.
  16.  
  17.     I PLACE THIS FILE IN THE PUBLIC DOMAIN, SO EVERYTHING CONTAINED HERE
  18.         IS TOTALLY FREE FOR YOU TO EXPLORE AND USE. I DISCLAIM ANY AND ALL
  19.         EVENTS COMING OUT OF ANY POSSIBLE USE (OR LACK OF USE) OR EXISTANCE
  20.         OF THIS FILE. I WON'T BE LIABLE FOR ANYTHING RELATED TO THIS FILE,
  21.         OR ANY PRIOR OR FUTURE VERSION OF IT.
  22.  
  23.     All trademarks mentioned are property of their respective holders.
  24.  
  25.     - Merits -
  26.  
  27.     Heavily based on info on the file 3DS_08.TXT by Jim Pitts
  28.       (jp5@ukc.ac.uk)
  29.  
  30.     Basic material-related stuff digged up by Jare.
  31.     Track info stuff too.
  32.  
  33.     Thanks to the Egerter brothers of WGT fame and to Walken/Impact studios
  34.         for extra info, Rex Deathstar for support. And definitely to
  35.         Xanthome/Darkzone for you know why. And of course, respect to
  36.         Avatar/Legend Design for being here before all of us.
  37.  
  38.     For a cool example of actual reading of 3DS files, look no
  39.         further than 3DSCO20.ZIP by Mats Byggmastar aka. MRI. I
  40.         personally prefer using a table-driven modification of this
  41.         code, but both approaches are quite ok and his is much faster
  42.         to write and follow.
  43.  
  44.     Now only lack is someone to explain how to make use of all this
  45.         stuff i.e. how exactly is data stored, how spline interpolations
  46.         are performed, what are those things called quaternions, etc. And
  47.         also, maybe, dig the rest of the chunks until we are actually able
  48.         to write 3DS files instead of just being bored reading. There's
  49.         lots to do.
  50.  
  51.     If you decide to work on this further, please make your findings
  52.         public like we have already done, ok? Upload it to
  53.         x2ftp.oulu.fi, THE place for programming info, and/or to
  54.         ftp.cdrom.com. But please PUBLISH it!
  55.  
  56.     - Change log -
  57.  
  58.     V 1.2:
  59.         - Added change log to have some idea what's going on.
  60.         - Added pivot point reading inside tracks stuff.
  61.         - Info about spline flags on keyframes.
  62.         - Added face edge visibility info.
  63.         - Finally!! Those flags that mark when the texture is wrapping
  64.           around inside a face. This happens when you apply spherical
  65.           or cylindrical coordinates, the faces along the 0º axis don't
  66.           get proper mapping coords. Someone describe how to fix this?
  67.         - Added -quiet parm, only displays minimal chunk info.
  68.         - Object parent number is stored in CHUNK_TRACKOBJNAME.
  69.           This makes reference to the node number in CHUNK_OBJNUMBER.
  70.         - Object number changed to unsigned. Parent 65535 means none.
  71.         - Added CHUNK_PRJ and CHUNK_MLI to allow inspecting .PRJ and
  72.           .MLI files (they're basically the same chunks as .3DS).
  73.         - Added banner to identify myself, and disclaimer for "just in
  74.           case" possibilities.
  75.         - Corrected possible bug when chunklen == 0 (it was not a
  76.           chunk).
  77.         - Added several name descriptions of chunks. Use diff to find
  78.           all the new chunks.
  79. */
  80.  
  81. #include <stdlib.h>
  82. #include <stdio.h>
  83. #include <string.h>
  84.  
  85. #ifndef PI
  86. #define PI 3.141592687
  87. #endif
  88.  
  89. typedef unsigned char  byte;
  90. typedef unsigned short word;
  91. typedef unsigned long  dword;
  92.  
  93. typedef signed char  sbyte;
  94. typedef signed short sword;
  95. typedef signed long  sdword;
  96.  
  97. #pragma pack(2)
  98.  
  99. typedef struct {
  100.     word    id;
  101.     dword   len;
  102. } TChunkHeader, *PChunkHeader;
  103.  
  104. #pragma pack()
  105.  
  106. enum {
  107.     CHUNK_RGBF      = 0x0010,
  108.     CHUNK_RGBB      = 0x0011,
  109. //    CHUNK_RBGB2     = 0x0012,       // ?? NOT HLS.
  110.  
  111.     CHUNK_PRJ       = 0xC23D,
  112.     CHUNK_MLI       = 0x3DAA,
  113.  
  114.     CHUNK_MAIN      = 0x4D4D,
  115.         CHUNK_OBJMESH   = 0x3D3D,
  116.             CHUNK_BKGCOLOR  = 0x1200,
  117.             CHUNK_AMBCOLOR  = 0x2100,
  118.             CHUNK_OBJBLOCK  = 0x4000,
  119.                 CHUNK_TRIMESH   = 0x4100,
  120.                     CHUNK_VERTLIST  = 0x4110,
  121.                     CHUNK_FACELIST  = 0x4120,
  122.                     CHUNK_FACEMAT   = 0x4130,
  123.                     CHUNK_MAPLIST   = 0x4140,
  124.                     CHUNK_SMOOLIST  = 0x4150,
  125.                     CHUNK_TRMATRIX  = 0x4160,
  126.                 CHUNK_LIGHT     = 0x4600,
  127.                     CHUNK_SPOTLIGHT = 0x4610,
  128.                 CHUNK_CAMERA    = 0x4700,
  129.                 CHUNK_HIERARCHY = 0x4F00,
  130.         CHUNK_VIEWPORT  = 0x7001,
  131.         CHUNK_MATERIAL  = 0xAFFF,
  132.             CHUNK_MATNAME   = 0xA000,
  133.             CHUNK_AMBIENT   = 0xA010,
  134.             CHUNK_DIFFUSE   = 0xA020,
  135.             CHUNK_SPECULAR  = 0xA030,
  136.             CHUNK_TEXTURE   = 0xA200,
  137.             CHUNK_BUMPMAP   = 0xA230,
  138.             CHUNK_MAPFILE   = 0xA300,
  139.         CHUNK_KEYFRAMER = 0xB000,
  140.             CHUNK_AMBIENTKEY    = 0xB001,
  141.             CHUNK_TRACKINFO = 0xB002,
  142.                 CHUNK_TRACKOBJNAME  = 0xB010,
  143.                 CHUNK_TRACKPIVOT    = 0xB013,
  144.                 CHUNK_TRACKPOS      = 0xB020,
  145.                 CHUNK_TRACKROTATE   = 0xB021,
  146.                 CHUNK_TRACKSCALE    = 0xB022,
  147.                 CHUNK_OBJNUMBER     = 0xB030,
  148.             CHUNK_TRACKCAMERA = 0xB003,
  149.                 CHUNK_TRACKFOV  = 0xB023,
  150.                 CHUNK_TRACKROLL = 0xB024,
  151.             CHUNK_TRACKCAMTGT = 0xB004,
  152.             CHUNK_TRACKLIGHT  = 0xB005,
  153.             CHUNK_TRACKLIGTGT = 0xB006,
  154.             CHUNK_TRACKSPOTL  = 0xB007,
  155.             CHUNK_FRAMES    = 0xB008,
  156.  
  157.  
  158. };
  159.  
  160. // ------------------------------------
  161.  
  162.     // Forward declaration.
  163. void ChunkReader(FILE *f, int ind, long p);
  164.  
  165. void SkipReader(FILE *f, int ind, long p) {
  166. }
  167.  
  168. void RGBFReader (FILE *f, int ind, long p) {
  169.     float c[3];
  170.     if (fread(&c, sizeof(c), 1, f) != 1) return;
  171.     printf("%*s    Red: %f, Green: %f, Blue: %f\n", ind, "", c[0], c[1], c[2]);
  172. }
  173.  
  174. void RGBBReader (FILE *f, int ind, long p) {
  175.     byte c[3];
  176.     if (fread(&c, sizeof(c), 1, f) != 1) return;
  177.     printf("%*s    Red: %d, Green: %d, Blue: %d\n", ind, "", c[0], c[1], c[2]);
  178. }
  179.  
  180. void ASCIIZReader (FILE *f, int ind, long p) {
  181.     int c;
  182.  
  183.         // Read ASCIIZ name
  184.     while ( (c = fgetc(f)) != EOF && c != '\0')
  185.         putchar(c);
  186.     printf("\"\n");
  187. }
  188.  
  189. void ObjBlockReader (FILE *f, int ind, long p) {
  190.     int c;
  191.  
  192.         // Read ASCIIZ object name
  193.     printf("%*sObject name \"", ind, "");
  194.     ASCIIZReader(f, ind, p);
  195.         // Read rest of chunks inside this one.
  196.     ChunkReader(f, ind, p);
  197. }
  198.  
  199. void VertListReader (FILE *f, int ind, long p) {
  200.     word nv;
  201.     float c[3];
  202.  
  203.     if (fread(&nv, sizeof(nv), 1, f) != 1) return;
  204.     printf("%*sVertices: %d\n", ind, "", nv);
  205.     while (nv-- > 0) {
  206.         if (fread(&c, sizeof(c), 1, f) != 1) return;
  207.         printf("%*s    X: %f, Y: %f, Z: %f\n", ind, "", c[0], c[1], c[2]);
  208.     }
  209. }
  210.  
  211. void FaceListReader (FILE *f, int ind, long p) {
  212.     word nv;
  213.     word c[3];
  214.     word flags;
  215.  
  216.     if (fread(&nv, sizeof(nv), 1, f) != 1) return;
  217.     printf("%*sFaces: %d\n", ind, "", nv);
  218.     while (nv-- > 0) {
  219.         if (fread(&c, sizeof(c), 1, f) != 1) return;
  220.         if (fread(&flags, sizeof(flags), 1, f) != 1) return;
  221.         printf("%*s  A %d, B %d, C %d, 0x%X:",
  222.                ind, "", c[0], c[1], c[2], flags);
  223. //        printf("%*s    AB: %d, BC: %d, CA: %d, UWrap %d, VWrap %d\n",
  224. //               ind, "",
  225.         printf(" AB %d BC %d CA %d UWrap %d VWrap %d\n",
  226.                (flags & 0x04) != 0, (flags & 0x02) != 0, (flags & 0x01) != 0,
  227.                (flags & 0x08) != 0, (flags & 0x10) != 0);
  228.     }
  229.         // Read rest of chunks inside this one.
  230.     ChunkReader(f, ind, p);
  231. }
  232.  
  233. void FaceMatReader (FILE *f, int ind, long p) {
  234.     int c;
  235.     word n, nf;
  236.  
  237.         // Read ASCIIZ material name
  238.     printf("%*sMaterial name for faces: \"", ind, "");
  239.     ASCIIZReader(f, ind, p);
  240.  
  241.     if (fread(&n, sizeof(n), 1, f) != 1) return;
  242.     printf("%*sFaces with this material: %d\n", ind, "", n);
  243.     while (n-- > 0) {
  244.         if (fread(&nf, sizeof(nf), 1, f) != 1) return;
  245.         printf("%*s    Face %d\n",
  246.                ind, "", nf);
  247.     }
  248. }
  249.  
  250. void MapListReader (FILE *f, int ind, long p) {
  251.     word nv;
  252.     float c[2];
  253.  
  254.     if (fread(&nv, sizeof(nv), 1, f) != 1) return;
  255.     printf("%*sVertices: %d\n", ind, "", nv);
  256.     while (nv-- > 0) {
  257.         if (fread(&c, sizeof(c), 1, f) != 1) return;
  258.         printf("%*s    U: %f, V: %f\n", ind, "", c[0], c[1]);
  259.     }
  260. }
  261.  
  262. void SmooListReader (FILE *f, int ind, long p) {
  263.     dword s;
  264.     int i;
  265.  
  266.     while (ftell(f) < p) {
  267.         if (fread(&s, sizeof(s), 1, f) != 1) return;
  268.         printf("%*sSmoothing groups: ", ind, "");
  269.         for (i = 0; i < 32; i++)
  270.             if (s & (1 << i))
  271.                 printf("%d, ", i + 1);
  272.         printf("\n");
  273.     }
  274. }
  275.  
  276. void TrMatrixReader(FILE *f, int ind, long p) {
  277.     float rot[9];
  278.     float trans[3];
  279.     if (fread(&rot, sizeof(rot), 1, f) != 1) return;
  280.     printf("%*sRotation matrix:\n", ind, "");
  281.     printf("%*s    %f, %f, %f\n", ind, "", rot[0], rot[1], rot[2]);
  282.     printf("%*s    %f, %f, %f\n", ind, "", rot[3], rot[4], rot[5]);
  283.     printf("%*s    %f, %f, %f\n", ind, "", rot[6], rot[7], rot[8]);
  284.     if (fread(&trans, sizeof(trans), 1, f) != 1) return;
  285.     printf("%*sTranslation matrix: %f, %f, %f\n",
  286.            ind, "", trans[0], trans[1], trans[2]);
  287. }
  288.  
  289. void LightReader(FILE *f, int ind, long p) {
  290.     float c[3];
  291.     if (fread(&c, sizeof(c), 1, f) != 1) return;
  292.     printf("%*s    X: %f, Y: %f, Z: %f\n", ind, "", c[0], c[1], c[2]);
  293.         // Read rest of chunks inside this one.
  294.     ChunkReader(f, ind, p);
  295. }
  296.  
  297. void SpotLightReader(FILE *f, int ind, long p) {
  298.     float c[5];
  299.     if (fread(&c, sizeof(c), 1, f) != 1) return;
  300.     printf("%*s    Target X: %f, Y: %f, Z: %f; Hotspot %f, Falloff %f\n",
  301.            ind, "", c[0], c[1], c[2], c[3], c[4]);
  302. }
  303.  
  304. void CameraReader(FILE *f, int ind, long p) {
  305.     float c[8];
  306.     if (fread(&c, sizeof(c), 1, f) != 1) return;
  307.     printf("%*s    Position: X: %f, Y: %f, Z: %f\n", ind, "", c[0], c[1], c[2]);
  308.     printf("%*s    Target: X: %f, Y: %f, Z: %f\n", ind, "", c[3], c[4], c[5]);
  309.     printf("%*s    Bank: %f, Lens: %f\n", ind, "", c[6], c[7]);
  310. }
  311.  
  312. void MatNameReader (FILE *f, int ind, long p) {
  313.     int c;
  314.  
  315.         // Read ASCIIZ object name
  316.     printf("%*sMaterial name \"", ind, "");
  317.     ASCIIZReader(f, ind, p);
  318. }
  319.  
  320. void MapFileReader(FILE *f, int ind, long p) {
  321.     int c;
  322.  
  323.         // Read ASCIIZ filename
  324.     printf("%*sMap filename \"", ind, "");
  325.     ASCIIZReader(f, ind, p);
  326. }
  327.  
  328. void FramesReader(FILE *f, int ind, long p) {
  329.     dword c[2];
  330.     if (fread(&c, sizeof(c), 1, f) != 1) return;
  331.     printf("%*s    Start: %ld, End: %ld\n",
  332.            ind, "", c[0], c[1]);
  333. }
  334.  
  335. void TrackObjNameReader(FILE *f, int ind, long p) {
  336.     int c;
  337.     word w[2];
  338.     word parent;
  339.  
  340.         // Read ASCIIZ name
  341.     printf("%*sTrack object name \"", ind, "");
  342.     ASCIIZReader(f, ind, p);
  343.     if (fread(&w, sizeof(w), 1, f) != 1) return;
  344.     if (fread(&parent, sizeof(parent), 1, f) != 1) return;
  345.     printf("%*sObject name data: Flags 0x%X, 0x%X, Parent %d\n",
  346.            ind, "", w[0], w[1], parent);
  347. }
  348.  
  349. void PivotPointReader(FILE *f, int ind, long p) {
  350.     float pos[3];
  351.  
  352.     if (fread(&pos, sizeof(pos), 1, f) != 1) return;
  353.     printf("%*s  Pivot at X: %f, Y: %f, Z: %f\n",
  354.            ind, "",
  355.            pos[0], pos[1], pos[2]);
  356. }
  357.  
  358.     /* Key info flags for position, rotation and scaling:
  359.         Until I know the meaning of each bit in flags I assume all mean
  360.         a following float data.
  361.     */
  362.  
  363.         // NOTE THIS IS NOT A CHUNK, but A PART OF SEVERAL CHUNKS
  364. void SplineFlagsReader(FILE *f, int ind, word flags) {
  365.     int i;
  366.     float dat;
  367.  
  368.     for (i = 0; i < 16; i++) {
  369.         static const char *flagnames[] = {
  370.             "Tension",
  371.             "Continuity",
  372.             "Bias",
  373.             "Ease To",
  374.             "Ease From",
  375.         };
  376.         if (flags & (1 << i)) {
  377.             if (fread(&dat, sizeof(dat), 1, f) != 1) return;
  378.             if (i < sizeof(flagnames)/sizeof(*flagnames))
  379.                 printf("%*s             %-15s = %f\n",
  380.                        ind, "", flagnames[i], dat);
  381.             else
  382.                 printf("%*s             %-15s = %f\n",
  383.                        ind, "", "Unknown", dat);
  384.         }
  385.     }
  386. }
  387.  
  388. void TrackPosReader(FILE *f, int ind, long p) {
  389.     word n, nf;
  390.     float pos[3];
  391.     word unkown;
  392.     word flags;
  393.  
  394.     fseek(f, 10, SEEK_CUR);
  395.     if (fread(&n, sizeof(n), 1, f) != 1) return;
  396.     printf("%*sPosition keys: %d\n", ind, "", n);
  397.     fseek(f, 2, SEEK_CUR);
  398.     while (n-- > 0) {
  399.         if (fread(&nf, sizeof(nf), 1, f) != 1) return;
  400.         if (fread(&unkown, sizeof(unkown), 1, f) != 1) return;
  401.         if (fread(&flags, sizeof(flags), 1, f) != 1) return;
  402.         printf("%*s  Frame %3d: Flags 0x%X\n", ind, "", nf, flags);
  403.         SplineFlagsReader(f, ind, flags);
  404.         if (fread(&pos, sizeof(pos), 1, f) != 1) return;
  405.         printf("%*s             X: %f, Y: %f, Z: %f\n",
  406.                ind, "", pos[0], pos[1], pos[2]);
  407.     }
  408. }
  409.  
  410. void TrackRotReader(FILE *f, int ind, long p) {
  411.     word n, nf;
  412.     float pos[4];
  413.     word unkown;
  414.     word flags;
  415.  
  416.     fseek(f, 10, SEEK_CUR);
  417.     if (fread(&n, sizeof(n), 1, f) != 1) return;
  418.     printf("%*sRotation keys: %d\n", ind, "", n);
  419.     fseek(f, 2, SEEK_CUR);
  420.     while (n-- > 0) {
  421.         if (fread(&nf, sizeof(nf), 1, f) != 1) return;
  422.         if (fread(&unkown, sizeof(unkown), 1, f) != 1) return;
  423.         if (fread(&flags, sizeof(flags), 1, f) != 1) return;
  424.         printf("%*s  Frame %3d: Flags 0x%X\n", ind, "", nf, flags);
  425.         SplineFlagsReader(f, ind, flags);
  426.         if (fread(&pos, sizeof(pos), 1, f) != 1) return;
  427.         printf("%*s             Angle: %fº, X: %f, Y: %f, Z: %f\n",
  428.                ind, "", pos[0]*180.0/PI, pos[1], pos[2], pos[3]);
  429.     }
  430. }
  431.  
  432. void TrackScaleReader(FILE *f, int ind, long p) {
  433.     word n, nf;
  434.     float pos[3];
  435.     word unkown;
  436.     word flags;
  437.  
  438.     fseek(f, 10, SEEK_CUR);
  439.     if (fread(&n, sizeof(n), 1, f) != 1) return;
  440.     printf("%*sScale keys: %d\n", ind, "", n);
  441.     fseek(f, 2, SEEK_CUR);
  442.     while (n-- > 0) {
  443.         if (fread(&nf, sizeof(nf), 1, f) != 1) return;
  444.         if (fread(&unkown, sizeof(unkown), 1, f) != 1) return;
  445.         if (fread(&flags, sizeof(flags), 1, f) != 1) return;
  446.         printf("%*s  Frame %3d: Flags 0x%X\n", ind, "", nf, flags);
  447.         SplineFlagsReader(f, ind, flags);
  448.         if (fread(&pos, sizeof(pos), 1, f) != 1) return;
  449.         printf("%*s            X: %f, Y: %f, Z: %f\n",
  450.                ind, "", pos[0], pos[1], pos[2]);
  451.     }
  452. }
  453.  
  454. void ObjNumberReader(FILE *f, int ind, long p) {
  455.     word n;
  456.  
  457.     if (fread(&n, sizeof(n), 1, f) != 1) return;
  458.     printf("%*sObject number: %d\n", ind, "", n);
  459. }
  460.  
  461.  
  462. // ------------------------------------
  463.  
  464. struct {
  465.     word id;
  466.     const char *name;
  467.     void (*func)(FILE *f, int ind, long p);
  468. } ChunkNames[] = {
  469.     {CHUNK_RGBF,        "RGB float",        RGBFReader},
  470.     {CHUNK_RGBB,        "RGB byte",         RGBBReader},
  471.  
  472.     {CHUNK_PRJ,         "Project",          NULL},
  473.     {CHUNK_MLI,         "Material Library", NULL},
  474.  
  475.     {CHUNK_MAIN,        "Main",             NULL},
  476.     {CHUNK_OBJMESH,     "Object Mesh",      NULL},
  477.     {CHUNK_BKGCOLOR,    "Background color", NULL},
  478.     {CHUNK_AMBCOLOR,    "Ambient color",    NULL},
  479.     {CHUNK_OBJBLOCK,    "Object Block",     ObjBlockReader},
  480.     {CHUNK_TRIMESH,     "Tri-Mesh",         NULL},
  481.     {CHUNK_VERTLIST,    "Vertex list",      VertListReader},
  482.     {CHUNK_FACELIST,    "Face list",        FaceListReader},
  483.     {CHUNK_FACEMAT,     "Face material",    FaceMatReader},
  484.     {CHUNK_MAPLIST,     "Mappings list",    MapListReader},
  485.     {CHUNK_SMOOLIST,    "Smoothings",       SmooListReader},
  486.     {CHUNK_TRMATRIX,    "Matrix",           TrMatrixReader},
  487.     {CHUNK_LIGHT,       "Light",            LightReader},
  488.     {CHUNK_SPOTLIGHT,   "Spotlight",        SpotLightReader},
  489.     {CHUNK_CAMERA,      "Camera",           CameraReader},
  490.     {CHUNK_HIERARCHY,   "Hierarchy",        NULL},
  491.  
  492.     {CHUNK_VIEWPORT,    "Viewport info",    NULL},
  493.     {CHUNK_MATERIAL,    "Material",         NULL},
  494.     {CHUNK_MATNAME,     "Material name",    MatNameReader},
  495.     {CHUNK_AMBIENT,     "Ambient color",    NULL},
  496.     {CHUNK_DIFFUSE,     "Diffuse color",    NULL},
  497.     {CHUNK_SPECULAR,    "Specular color",   NULL},
  498.     {CHUNK_TEXTURE,     "Texture map",      NULL},
  499.     {CHUNK_BUMPMAP,     "Bump map",         NULL},
  500.     {CHUNK_MAPFILE,     "Map filename",     MapFileReader},
  501.  
  502.     {CHUNK_KEYFRAMER,   "Keyframer data",   NULL},
  503.     {CHUNK_AMBIENTKEY,  "Ambient key",      NULL},
  504.     {CHUNK_TRACKINFO,   "Track info",       NULL},
  505.     {CHUNK_FRAMES,      "Frames",           FramesReader},
  506.     {CHUNK_TRACKOBJNAME,"Track Obj. Name",  TrackObjNameReader},
  507.     {CHUNK_TRACKPIVOT,  "Pivot point",      PivotPointReader},
  508.     {CHUNK_TRACKPOS,    "Position keys",    TrackPosReader},
  509.     {CHUNK_TRACKROTATE, "Rotation keys",    TrackRotReader},
  510.     {CHUNK_TRACKSCALE,  "Scale keys",       TrackScaleReader},
  511.     {CHUNK_OBJNUMBER,   "Object number",    ObjNumberReader},
  512.  
  513.     {CHUNK_TRACKCAMERA, "Camera track",             NULL},
  514.     {CHUNK_TRACKCAMTGT, "Camera target track",      NULL},
  515.     {CHUNK_TRACKLIGHT,  "Pointlight track",         NULL},
  516.     {CHUNK_TRACKLIGTGT, "Pointlight target track",  NULL},
  517.     {CHUNK_TRACKSPOTL,  "Spotlight track",          NULL},
  518.     {CHUNK_TRACKFOV,    "FOV track",                NULL},
  519.     {CHUNK_TRACKROLL,   "Roll track",               NULL},
  520. };
  521.  
  522. int FindChunk(word id) {
  523.     int i;
  524.     for (i = 0; i < sizeof(ChunkNames)/sizeof(ChunkNames[0]); i++)
  525.         if (id == ChunkNames[i].id)
  526.             return i;
  527.     return -1;
  528. }
  529.  
  530. // ------------------------------------
  531.  
  532. int Verbose = 0;
  533. int Quiet   = 0;
  534.  
  535. void ChunkReader(FILE *f, int ind, long p) {
  536.     TChunkHeader h;
  537.     int n;
  538.     long pc;
  539.  
  540.     while (ftell(f) < p) {
  541.         pc = ftell(f);
  542.         if (fread(&h, sizeof(h), 1, f) != 1) return;
  543.         if (h.len == 0) return;
  544.         n = FindChunk(h.id);
  545.         if (n < 0) {
  546.             if (Verbose)
  547.                 printf("%*sUnknown chunk: 0x%04X, offset 0x%lX, size: %d bytes.\n",
  548.                        ind, "", h.id, pc, h.len);
  549.             fseek(f, pc + h.len, SEEK_SET);
  550.         } else {
  551.             if (!Quiet || ChunkNames[n].func == NULL)
  552.                 printf("%*sChunk type \"%s\", offset 0x%lX, size %d bytes\n",
  553.                        ind, "", ChunkNames[n].name, pc, h.len);
  554.             pc = pc + h.len;
  555.             if (ChunkNames[n].func != NULL)
  556.                 ChunkNames[n].func(f, ind + 2, pc);
  557.             else
  558.                 ChunkReader(f, ind + 2, pc);
  559.             fseek(f, pc, SEEK_SET);
  560.         }
  561.         if (ferror(f))
  562.             break;
  563.     }
  564. }
  565.  
  566. // ------------------------------------
  567.  
  568. void Banner(void) {
  569.     printf("3DSRDR, 3D Studio formats reader v1.2 by Javier Arevalo AKA Jare/Iguana.\n\n");
  570. }
  571.  
  572. void main(int argc, char *argv[]) {
  573.     FILE *f;
  574.     long p;
  575.  
  576.     if (argc < 2) {
  577.         Banner();
  578.         printf("Usage: 3DSRDR file.3DS (or .PRJ or .MLI) [-quiet or -verbose]\n");
  579.         exit(1);
  580.     }
  581.  
  582.     f = fopen(argv[1], "rb");
  583.     if (f == NULL) {
  584.         Banner();
  585.         printf("Can't open %s!\n", argv[1]);
  586.         exit(1);
  587.     }
  588.  
  589.     if (argc > 2 && strcmp(argv[2], "-verbose") == 0)
  590.         Verbose = 1;
  591.     if (argc > 2 && strcmp(argv[2], "-quiet") == 0)
  592.         Quiet = 1;
  593.     if (!Quiet)
  594.         Banner();
  595.  
  596.         // Find file size.
  597.     fseek(f, 0, SEEK_END);
  598.     p = ftell(f);
  599.     fseek(f, 0, SEEK_SET);
  600.         // Go!
  601.     ChunkReader(f, 0, p);
  602. }
  603.  
  604.